控制流(Control Flow) 决定了代码的执行顺序和逻辑分支。
根据 Bohm-Jacopini 定理,程序有三种基本控制结构:
| 结构 | 描述 | 关键字 |
|---|---|---|
| 顺序结构 | 语句按顺序依次执行 | (默认) |
| 选择结构 | 根据条件选择执行路径 | if-elif-else |
| 循环结构 | 重复执行某段代码 | for / while |
布尔(Boolean)代数是条件判断的数学基础:
| 运算 | 语法 | 含义 |
|---|---|---|
| 与(AND) | A and B |
两者都真才真 |
| 或(OR) | A or B |
至少一个真就真 |
| 非(NOT) | not A |
真变假,假变真 |
短路求值(Short-circuit Evaluation):
A and B:如果 A 为假,不计算 BA or B:如果 A 为真,不计算 B累进税率是现代税收制度的核心,体现’量能课税’原则:
核心公式:
\[应纳税额 = 应纳税所得额 \times 税率 - 速算扣除数\]
def calculate_tax(salary):
"""
计算个人所得税(简化版)
中国个人所得税采用7级超额累进税率
"""
# 使用if-elif-else匹配累进税率表
if salary <= 3000:
rate, deduction = 0, 0
elif salary <= 12000:
rate, deduction = 0.03, 0
elif salary <= 25000:
rate, deduction = 0.10, 210
elif salary <= 35000:
rate, deduction = 0.20, 1410
elif salary <= 55000:
rate, deduction = 0.25, 2660
elif salary <= 80000:
rate, deduction = 0.30, 4410
else:
rate, deduction = 0.35, 7160
# 应纳税所得额 = 税前工资 - 起征点(5000元)
taxable_income = salary - 5000
# 应纳税额 = 应纳税所得额 × 税率 - 速算扣除数
tax = max(0, taxable_income * rate - deduction)
after_tax = salary - tax
return tax, after_tax
# 测试不同收入水平
salaries = [2500, 5000, 15000, 30000, 60000, 100000]
print('工资扣税计算:')
print('-' * 60)
for salary in salaries:
tax, after_tax = calculate_tax(salary)
tax_rate = tax / salary * 100 if salary > 0 else 0
print(f'税前工资: {salary:8.2f}元 | 税额: {tax:7.2f}元 | 税率: {tax_rate:5.2f}% | 税后: {after_tax:8.2f}元')工资扣税计算:
------------------------------------------------------------
税前工资: 2500.00元 | 税额: 0.00元 | 税率: 0.00% | 税后: 2500.00元
税前工资: 5000.00元 | 税额: 0.00元 | 税率: 0.00% | 税后: 5000.00元
税前工资: 15000.00元 | 税额: 790.00元 | 税率: 5.27% | 税后: 14210.00元
税前工资: 30000.00元 | 税额: 3590.00元 | 税率: 11.97% | 税后: 26410.00元
税前工资: 60000.00元 | 税额: 12090.00元 | 税率: 20.15% | 税后: 47910.00元
税前工资: 100000.00元 | 税额: 26090.00元 | 税率: 26.09% | 税后: 73910.00元
elif 是 ‘else if’ 的缩写当需要同时满足多个条件时:
| 写法 | 代码 | 适用场景 |
|---|---|---|
| 嵌套 if | if A: → if B: |
条件有层级关系 |
| 逻辑运算 | if A and B: |
条件独立并列 |
选择建议:代码可读性优先
策略逻辑(多条件嵌套判断):
def generate_signal(price, ma20, ma60, volume, avg_volume, rsi):
"""基于技术指标的多条件嵌套判断"""
signal = 'HOLD'
reason = []
# 第一层:判断市场趋势(均线排列)
if ma20 > ma60:
reason.append('均线多头')
# 第二层:价格是否突破均线
if price > ma20:
reason.append('突破20日均线')
# 第三层:量价配合 + RSI确认
if volume > avg_volume * 1.2 and rsi < 70:
signal = 'BUY'
reason.append('放量上涨')
elif ma20 < ma60:
reason.append('均线空头')
if price < ma20:
reason.append('跌破20日均线')
if volume > avg_volume * 1.2 and rsi > 30:
signal = 'SELL'
reason.append('放量下跌')
else:
reason.append('均线纠缠,观望')
return signal, '; '.join(reason)
# 测试不同市场情景
signals = [
(18.5, 18.0, 17.5, 2500000, 2000000, 45),
(18.5, 18.0, 17.5, 1500000, 2000000, 65),
(18.5, 18.0, 17.5, 2500000, 2000000, 75),
(16.5, 18.0, 17.5, 2500000, 2000000, 25),
]
print('交易信号分析:')
print('-' * 80)
for price, ma20, ma60, volume, avg_vol, rsi in signals:
signal, reason = generate_signal(price, ma20, ma60, volume, avg_vol, rsi)
print(f'价格={price:.1f}, MA20={ma20:.1f}, MA60={ma60:.1f}, 信号={signal}, 原因=[{reason}]')交易信号分析:
--------------------------------------------------------------------------------
价格=18.5, MA20=18.0, MA60=17.5, 信号=BUY, 原因=[均线多头; 突破20日均线; 放量上涨]
价格=18.5, MA20=18.0, MA60=17.5, 信号=HOLD, 原因=[均线多头; 突破20日均线]
价格=18.5, MA20=18.0, MA60=17.5, 信号=HOLD, 原因=[均线多头; 突破20日均线]
价格=16.5, MA20=18.0, MA60=17.5, 信号=HOLD, 原因=[均线多头]
for 循环用于遍历序列中的每个元素:
range() 函数生成整数序列:
| 用法 | 说明 | 示例 |
|---|---|---|
range(stop) |
0 到 stop-1 | range(5) → 0,1,2,3,4 |
range(start, stop) |
start 到 stop-1 | range(1,5) → 1,2,3,4 |
range(start, stop, step) |
自定义步长 | range(0,10,2) → 0,2,4,6,8 |
复利是金融学的核心概念:利息产生利息。
\[FV = PV \times (1 + r)^n\]
import numpy as np
# ===== 案例1:复利终值计算 =====
principal = 10000 # 本金
rate = 0.05 # 年利率5%
years = 10 # 投资10年
print('复利增长过程:')
print('-' * 50)
print(f'{"年份":<6}{"年初本金":<12}{"利息":<12}{"年末余额":<12}')
print('-' * 50)
amount = principal
# range(1, years+1) 生成 [1,2,...,10]
for year in range(1, years + 1):
interest = amount * rate # 当年利息
amount += interest # 累加到余额
print(f'{year:<6}{amount - interest:<12.2f}{interest:<12.2f}{amount:<12.2f}')
# 复利 vs 单利对比
print(f'\n复利终值: {amount:.2f}元')
simple_interest = principal * (1 + rate * years)
print(f'单利对比: {simple_interest:.2f}元')
print(f'复利优势: {amount - simple_interest:.2f}元')复利增长过程:
--------------------------------------------------
年份 年初本金 利息 年末余额
--------------------------------------------------
1 10000.00 500.00 10500.00
2 10500.00 525.00 11025.00
3 11025.00 551.25 11576.25
4 11576.25 578.81 12155.06
5 12155.06 607.75 12762.82
6 12762.82 638.14 13400.96
7 13400.96 670.05 14071.00
8 14071.00 703.55 14774.55
9 14774.55 738.73 15513.28
10 15513.28 775.66 16288.95
复利终值: 16288.95元
单利对比: 15000.00元
复利优势: 1288.95元
import numpy as np
# 日收益率序列(10个交易日)
daily_returns = [0.02, -0.01, 0.03, -0.02, 0.01, 0.04, -0.03, 0.02, -0.01, 0.01]
# ===== 手动计算标准差 =====
n = len(daily_returns)
mean_return = sum(daily_returns) / n
# 列表推导式计算方差
variance = sum([(r - mean_return) ** 2 for r in daily_returns]) / (n - 1)
volatility_daily = np.sqrt(variance)
# 年化波动率 = 日波动率 × √252
volatility_annual = volatility_daily * np.sqrt(252)
print(f'日收益率: {daily_returns}')
print(f'均值: {mean_return:.4f}')
print(f'手动计算年化波动率: {volatility_annual:.4f}')
print(f'NumPy计算年化波动率: {np.std(daily_returns) * np.sqrt(252):.4f}')日收益率: [0.02, -0.01, 0.03, -0.02, 0.01, 0.04, -0.03, 0.02, -0.01, 0.01]
均值: 0.0060
手动计算年化波动率: 0.3604
NumPy计算年化波动率: 0.3419
核心优势:
while 循环在条件为真时重复执行:
金融应用:迭代求解(牛顿法、梯度下降)
\[x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)}\]
import numpy as np
def sqrt_newton(x, tolerance=1e-6, max_iter=100):
"""
牛顿迭代法计算√2
迭代公式: x_{n+1} = 0.5 * (x_n + S/x_n)
"""
S = 2.0
x_old = x
print(f'牛顿法求√{S}:')
print(f'{"迭代":<6}{"近似值":<15}{"误差":<15}')
print('-' * 40)
for i in range(max_iter):
x_new = 0.5 * (x_old + S / x_old) # 牛顿迭代
error = abs(x_new - x_old) # 绝对误差
print(f'{i+1:<6}{x_new:<15.10f}{error:<15.10f}')
if error < tolerance: # 检查收敛
print(f'\n收敛! 迭代{i+1}次后达到精度要求')
break
x_old = x_new
else:
print(f'\n警告: 未在{max_iter}次内收敛')
return x_new
sqrt_approx = sqrt_newton(1.0)
sqrt_actual = np.sqrt(2)
print(f'\n近似值: {sqrt_approx:.10f}')
print(f'实际值: {sqrt_actual:.10f}')
print(f'误差: {abs(sqrt_approx - sqrt_actual):.2e}')牛顿法求√2.0:
迭代 近似值 误差
----------------------------------------
1 1.5000000000 0.5000000000
2 1.4166666667 0.0833333333
3 1.4142156863 0.0024509804
4 1.4142135624 0.0000021239
5 1.4142135624 0.0000000000
收敛! 迭代5次后达到精度要求
近似值: 1.4142135624
实际值: 1.4142135624
误差: 2.22e-16
核心要点:
金融应用:隐含波动率
import numpy as np
def implied_volatility(option_price, S, K, T, r=0.05, max_iter=100):
"""
使用牛顿法求期权隐含波动率(简化版)
牛顿迭代: σ_{n+1} = σ_n - (BS(σ_n) - MarketPrice) / Vega(σ_n)
"""
sigma = 0.3 # 初始猜测30%
tolerance = 1e-6
for i in range(max_iter):
# 简化版演示(实际需完整Black-Scholes + Vega)
price_diff = option_price - (S * 0.6)
sigma_new = sigma + price_diff * 0.1
if abs(sigma_new - sigma) < tolerance:
break
sigma = sigma_new
return sigma
print('隐含波动率计算:')
print('期权价格: 5.0元, 标的价格: 100元')
iv = implied_volatility(5.0, 100, 105, 1)
print(f'隐含波动率: {iv:.2%}')隐含波动率计算:
期权价格: 5.0元, 标的价格: 100元
隐含波动率: -54970.00%
| 语句 | 作用 | 类比 |
|---|---|---|
break |
立即退出整个循环 | 紧急刹车 |
continue |
跳过本次迭代,继续下一次 | 跳过一站 |
# ===== break演示 =====
print('break演示(找到第一个正收益):')
returns = [-0.02, 0.03, -0.01, 0.04, 0.01, -0.03, 0.02]
for i, ret in enumerate(returns):
if ret > 0:
print(f' 第{i+1}天: {ret:.2%}')
break # 找到后立即退出
# ===== continue演示 =====
print('\ncontinue演示(跳过负收益):')
positive_count = 0
for ret in returns:
if ret < 0:
continue # 负收益直接跳过
positive_count += 1
print(f' 正收益: {ret:.2%}')
print(f'\n正收益天数: {positive_count}天')break演示(找到第一个正收益):
第2天: 3.00%
continue演示(跳过负收益):
正收益: 3.00%
正收益: 4.00%
正收益: 1.00%
正收益: 2.00%
正收益天数: 4天
for-else 规则:
else 块在循环正常完成时执行break 中断,else 块不会执行*args*args 收集所有位置参数为元组,使函数能接受任意数量的参数:
折现公式:
\[PV = \sum_{t=1}^{n} \frac{CF_t}{(1+r)^t}\]
def PV(R, *NCF, verbose=False):
"""
计算现金流现值
PV = Σ(CF_t / (1+r)^t)
*NCF 接受任意数量的现金流
"""
pv = 0
n = 1
print('现值计算过程:') if verbose else None
print('-' * 60) if verbose else None
for cf in NCF:
discount_factor = 1 / (1 + R) ** n
discounted_cf = cf * discount_factor
pv += discounted_cf
if verbose:
print(f' 第{n}期: 现金流={cf:8.2f}, 折现因子={discount_factor:.6f}, 现值={discounted_cf:8.2f}')
n += 1
if verbose:
print('-' * 60)
print(f'现值总和: {pv:.2f}元')
return pv
# 案例1:简单投资项目
print('案例1: 投资项目现金流')
pv1 = PV(0.05, -10000, 8000, 12000)
print(f'NPV(净现值): {pv1:.2f}元\n')
# 案例2:多期项目
print('案例2: 多期项目')
project_flows = [-50000, 10000, 15000, 20000, 25000, 30000]
pv2 = PV(0.08, *project_flows, verbose=True)
# 案例3:债券定价
print('\n案例3: 债券定价')
bond_flows = [50] * 9 + [1050] # 10年期,票面5%,面值1000
pv_bond = PV(0.06, *bond_flows)
print(f'债券现值: {pv_bond:.2f}元\n')案例1: 投资项目现金流
NPV(净现值): 8098.48元
案例2: 多期项目
现值计算过程:
------------------------------------------------------------
第1期: 现金流=-50000.00, 折现因子=0.925926, 现值=-46296.30
第2期: 现金流=10000.00, 折现因子=0.857339, 现值= 8573.39
第3期: 现金流=15000.00, 折现因子=0.793832, 现值=11907.48
第4期: 现金流=20000.00, 折现因子=0.735030, 现值=14700.60
第5期: 现金流=25000.00, 折现因子=0.680583, 现值=17014.58
第6期: 现金流=30000.00, 折现因子=0.630170, 现值=18905.09
------------------------------------------------------------
现值总和: 24804.84元
案例3: 债券定价
债券现值: 926.40元
递归三要素:
数学归纳法的程序化实现:
\[n! = n \times (n-1)!\]
\[F(n) = F(n-1) + F(n-2)\]
import numpy as np
# ===== 阶乘 =====
def factorial(n):
"""n! = n × (n-1)!,基准: 0!=1, 1!=1"""
if n <= 1:
return 1
return n * factorial(n - 1)
print('阶乘计算:')
for n in [1, 5, 10, 20]:
print(f'{n}! = {factorial(n)}')
# ===== 斐波那契 =====
def fibonacci(n):
"""F(0)=0, F(1)=1, F(n)=F(n-1)+F(n-2)"""
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(f'\n斐波那契数列前10项:')
print([fibonacci(i) for i in range(10)])阶乘计算:
1! = 1
5! = 120
10! = 3628800
20! = 2432902008176640000
斐波那契数列前10项:
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
import numpy as np
def binomial_tree(S, K, T, r, sigma, n, call=True):
"""
Cox-Ross-Rubinstein二叉树模型
u = e^(σ√dt), d = 1/u, p = (e^(r·dt) - d) / (u - d)
"""
dt = T / n
u = np.exp(sigma * np.sqrt(dt)) # 上涨因子
d = 1 / u # 下跌因子
p = (np.exp(r * dt) - d) / (u - d) # 风险中性概率
# 终端节点期权价值
option_values = np.zeros(n + 1)
for j in range(n + 1):
S_T = S * (u ** j) * (d ** (n - j))
if call:
option_values[j] = max(S_T - K, 0)
else:
option_values[j] = max(K - S_T, 0)
# 从终端向根回推
for i in range(n - 1, -1, -1):
for j in range(i + 1):
option_values[j] = np.exp(-r * dt) * (
p * option_values[j + 1] + (1 - p) * option_values[j]
)
return option_values[0]
# 注:生产环境中可使用n=100或更高步数以提升精度
option_price = binomial_tree(S=100, K=105, T=1, r=0.05, sigma=0.2, n=20)
print(f'二叉树模型期权价格: {option_price:.2f}元')二叉树模型期权价格: 8.11元
| 方法 | 时间复杂度 | 说明 |
|---|---|---|
| 朴素递归 | \(O(2^n)\) | 指数级,大量重复计算 |
| 动态规划 | \(O(n^2)\) / \(O(n)\) | 避免重复,从底向上 |
最佳实践:金融应用中必须优化递归
Python 变量查找遵循 LEGB 层次:
| 层级 | 名称 | 范围 |
|---|---|---|
| L (Local) | 局部作用域 | 函数内 |
| E (Enclosing) | 闭包作用域 | 嵌套函数的外层 |
| G (Global) | 模块作用域 | 文件内 |
| B (Built-in) | 内置作用域 | Python 内置 |
x = 10 # 全局变量
y = 20
def func_local():
"""局部变量遮蔽全局变量"""
x = 5 # 局部变量,不影响全局x
print(f'函数内x: {x} (局部)')
def func_global():
"""使用global修改全局变量"""
global y
y = 50
print(f'函数内y: {y} (修改后的全局)')
def func_enclosing():
"""闭包:内层函数访问外层变量"""
z = 100
def inner():
return x + z # x来自Global, z来自Enclosing
return inner()
print('初始状态:')
print(f'全局x: {x}, 全局y: {y}')
func_local()
print(f'func_local()后, 全局x: {x} (未改变)')
func_global()
print(f'func_global()后, 全局y: {y} (已修改)')
print(f'闭包结果: {func_enclosing()}')
# 错误示例:忘记global
def modify_global_wrong():
y = 30 # 创建局部变量,不影响全局y
print(f'\n错误示例测试:')
print(f'修改前全局y: {y}')
modify_global_wrong()
print(f'modify_global_wrong()后, 全局y: {y} (未修改,因为没有global)')初始状态:
全局x: 10, 全局y: 20
函数内x: 5 (局部)
func_local()后, 全局x: 10 (未改变)
函数内y: 50 (修改后的全局)
func_global()后, 全局y: 50 (已修改)
闭包结果: 110
错误示例测试:
修改前全局y: 50
modify_global_wrong()后, 全局y: 50 (未修改,因为没有global)
global(除非绝对必要),防止代码维护困难lambda 是匿名的单行函数:
| 特点 | 说明 |
|---|---|
| 匿名 | 不需要函数名 |
| 简洁 | 只能是单个表达式 |
| 函数式 | 可作为参数传递给高阶函数 |
# 基本lambda函数
square = lambda x: x**2
cube = lambda x: x**3
print('lambda函数演示:')
print(f'平方: {square(5)} = {square(5)}')
print(f'立方: {cube(5)} = {cube(5)}')
# 金融收益率计算
simple_return = lambda initial, final: (final - initial) / initial
compound_return = lambda initial, rate, periods: initial * (1 + rate) ** periods - initial
print(f'\n简单收益率: {simple_return(100, 110):.2%}')
print(f'复利收益: {compound_return(10000, 0.05, 10):.2f}')
# 投资组合净值
net_value = lambda prices, shares: sum(p * s for p, s in zip(prices, shares))
prices = [10.5, 22.3, 15.8]
shares = [100, 200, 150]
print(f'\n投资组合净值: {net_value(prices, shares):.2f}元')lambda函数演示:
平方: 25 = 25
立方: 125 = 125
简单收益率: 10.00%
复利收益: 6288.95
投资组合净值: 7880.00元
stocks = ['贵州茅台', '五粮液', '招商银行']
prices = [1850, 220, 45]
# map:对每个元素应用函数
formatted = list(map(lambda x: f'{x}元', prices))
print(f'格式化价格: {formatted}')
# filter:过滤符合条件的元素
expensive = list(filter(lambda p: p[1] > 200, zip(stocks, prices)))
print(f'高价股票: {[s + "=" + str(p) + "元" for s, p in expensive]}')
# sorted:自定义排序
portfolio = [
{'name': '贵州茅台', 'return': 0.15},
{'name': '五粮液', 'return': 0.08},
{'name': '招商银行', 'return': 0.12}
]
sorted_portfolio = sorted(portfolio, key=lambda x: x['return'], reverse=True)
print(f'\n按收益率排序:')
for stock in sorted_portfolio:
print(f" {stock['name']}: {stock['return']:.2%}")格式化价格: ['1850元', '220元', '45元']
高价股票: ['贵州茅台=1850元', '五粮液=220元']
按收益率排序:
贵州茅台: 15.00%
招商银行: 12.00%
五粮液: 8.00%
交易信号:
收益率= 6.00%: 信号=BUY
收益率=-3.00%: 信号=SELL
收益率= 2.00%: 信号=HOLD
收益率=-1.00%: 信号=HOLD
收益率= 8.00%: 信号=BUY
| 场景 | 推荐 | 原因 |
|---|---|---|
| 简单单行逻辑 | ✅ lambda | 简洁高效 |
| 高阶函数参数 | ✅ lambda | 避免定义独立函数 |
| 复杂多行逻辑 | ❌ 用 def |
可读性优先 |
| 需要文档字符串 | ❌ 用 def |
lambda 无法添加 docstring |
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
#题目一
salary = 8000 # 基本工资
if salary <= 5000: # 判断基本工资是否小于等于5000
rate = 0 # 基本工资小于等于5000,不扣税,即扣税率为0%
else: # 不满足以上条件时
rate = 0.05 # 基本工资大于5000,扣税率为0.05,即5%
# 计算税后工资,基本工资-扣税,扣税额为超过3000部分的乘以扣税率
salary = salary - (salary - 5000) * rate
print("税后工资为:%d" % salary) # 将税后工资打印输出税后工资为:7850
# 注:该代码块包含input()交互输入,渲染时无法执行
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
#题目二
sum_salary = 0
salary_list = [] # 定义列表salary_list
salary = 0 # 初始化薪资变量为0
while True: # 条件循环
salary = input('请输入员工的薪资,输入Q结束计算:') # 获取用户键盘输入
if salary.upper() == 'Q': # 条件判断:salary.upper() == 'Q'
print('程序结束') # 输出程序结束
break # 跳出循环
elif int(salary) <= 0: # 否则判断:int(salary) <= 0
print('您输入的数值有误,请重新输入') # 输出您输入的数值有误,请重新输入
continue # 跳过本次迭代
salary_list.append(salary) # 将有效薪资数据添加到列表
sum_salary += int(salary) # 更新sum_salary的值
print(len(salary_list)) # 输出数据长度
print(sum_salary) # 输出薪资数据# 注:该代码块包含缩进错误的填空代码,需要在平台上完成
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
#题目三
Ri=[0.15,0.20,-0.10,0.35] #收益率序列
Ai=[0.3,0.2,0.3,0.2] #权重序列
TR=0 # 初始化投资组合期望报酬率为0
for j in range(len(Ri)): # 遍历range(len(Ri))中的每个j
TRij=Ri[j]*Ai[j] # 计算第j项资产的加权收益贡献(收益率×权重)
TR+=TRij # 更新TR的值
print("投资组合的期望报酬率为:{:.2f}".format(TR)) # 输出投资组合的期望报酬率为:{:.2f}[商业大数据分析与应用]